
import { BitMath } from "../math/math";
import { Adapter_Interface } from "./adapter_interface";
export namespace Adapter_Impl_Canvas2d
{
    export class RenderAdapter_Canvas2d implements Adapter_Interface.IRenderAdapter
    {
        get viewwidth(): number
        {
            return this.rootCanvas.canvas.width;
        }
        get viewheight(): number
        {
            return this.rootCanvas.canvas.height;
        }
        rootCanvas: CanvasRenderingContext2D;
        backCanvasCreator: (width: number, height: number) => OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
        public constructor(rootCanvas: CanvasRenderingContext2D,
            backCanvasCreator: (width: number, height: number) => OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D)
        {
            this.rootCanvas = rootCanvas;
            this.rootCanvas.imageSmoothingEnabled = false;

            this.backCanvasCreator = backCanvasCreator;
        }

        CreateWriteableTexture(palette: BitMath.OutPalette, width: number, height: number): Adapter_Interface.ITexture_Writeable
        {
            var backc = this.backCanvasCreator(width, height);
            return new RenderAdapter_Canvas2d_Texture(backc, palette, width, height);
        }
        Clear(): void
        {
            this.rootCanvas.clearRect(0, 0, this.rootCanvas.canvas.width, this.rootCanvas.canvas.height);
        }
        Flush(): void
        {

        }
        Draw(tex: Adapter_Interface.ITexture | HTMLImageElement, srcrect: BitMath.Rect, x: number, y: number, colorIndexMultiply: number): void
        {

            if (tex instanceof HTMLImageElement)
            {
                this.rootCanvas.drawImage(tex, srcrect.x, srcrect.y, srcrect.w, srcrect.h,
                    x, y, srcrect.w, srcrect.h);
                return;
            }
            if (colorIndexMultiply == 0)
                this.rootCanvas.fillStyle = "#ffffff";
            else
                this.rootCanvas.fillStyle = tex.palette.GetColorStr(colorIndexMultiply);

            let canvas = (tex as RenderAdapter_Canvas2d_Texture).backCanvas.canvas;

            this.rootCanvas.drawImage(canvas, srcrect.x, srcrect.y, srcrect.w, srcrect.h,
                x, y, srcrect.w, srcrect.h);
        }
        DrawScale(tex: Adapter_Interface.ITexture, srcrect: BitMath.Rect, destrect: BitMath.Rect, colorIndexMultiply: number): void
        {
            
            if (tex instanceof HTMLImageElement)
            {
                this.rootCanvas.drawImage(tex, srcrect.x, srcrect.y, srcrect.w, srcrect.h,
                    destrect.x, destrect.y, destrect.w, destrect.h);

                return;
            }
            if (colorIndexMultiply == 0)
                this.rootCanvas.fillStyle = "#ffffff";
            else
                this.rootCanvas.fillStyle = tex.palette.GetColorStr(colorIndexMultiply);

            let canvas = (tex as RenderAdapter_Canvas2d_Texture).backCanvas.canvas;

            this.rootCanvas.drawImage(canvas, srcrect.x, srcrect.y, srcrect.w, srcrect.h,
                destrect.x, destrect.y, destrect.w, destrect.h);

        }
    }
    class RenderAdapter_Canvas2d_Texture implements Adapter_Interface.ITexture_Writeable
    {
        constructor(backCanvas: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D,
            palette: BitMath.OutPalette, width: number, height: number)
        {
            this.backCanvas = backCanvas;
            this.backCanvas.canvas.width = width;
            this.backCanvas.canvas.height = height;
            this._width = width;
            this._height = height;
            this._palette = palette;
            this.writedata = this.backCanvas.createImageData(8, 8);
        }
        backCanvas: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
        private _width: number;
        private _height: number;
        private _palette: BitMath.OutPalette;
        get width(): number
        {
            return this._width;
        }
        get height(): number
        {
            return this._height;
        }
        get bit(): number//32bit 还是8bit ，看是否支持Texture
        {
            return 32;
        }
        get palette(): BitMath.OutPalette//每个贴图有一个调色板，如果是8bit贴图，则适配层要硬件实现调色板，如果是32bit贴图，则适配层写入要做转换
        {
            return this._palette;
        }
        private writedata: ImageData;
        private writex: number = 0;
        private writey: number = 0;
        BeginWrite(x: number, y: number, w: number, h: number): void
        {

            if (w != this.writedata.width || h != this.writedata.height)
                this.writedata = this.backCanvas.createImageData(w, h);
            this.writex = x;
            this.writey = y;
        }
        Write8bitBlock(x: number, y: number, data: Uint8Array, datawidth: number): void
        {
            var width = Math.min(this.writedata.width - x, datawidth);

            var height = Math.min(this.writedata.height - y, (data.length / datawidth) | 0);
            for (var sy = 0; sy < height; sy++)
            {
                for (var sx = 0; sx < width; sx++)
                {
                    var i = ((sy + y) * this.writedata.width + (sx + x)) * 4;
                    var scolor = this.palette.GetColor(data[sy * datawidth + sx]);
                    this.writedata.data[i + 0] = scolor.r;
                    this.writedata.data[i + 1] = scolor.g;
                    this.writedata.data[i + 2] = scolor.b;
                    this.writedata.data[i + 3] = scolor.a;
                }
            }
        }
        Write8bitPixel(x: number, y: number, colorIndex: number): void
        {
            var i = (y * this.writedata.width + x) * 4;
            let color = this.palette.GetColor(colorIndex);
            this.writedata.data[i + 0] = color.r;
            this.writedata.data[i + 1] = color.g;
            this.writedata.data[i + 2] = color.b;
            this.writedata.data[i + 3] = color.a;
        }
        EndWrite(): void
        {
            this.backCanvas.putImageData(this.writedata, this.writex, this.writey);
        }

        Close(): void
        {
            this.backCanvas.canvas.width = 1;
            this.backCanvas.canvas.height = 1;
        }
    }

    export function CreateWebCanvasAdapter(rootCanvas: CanvasRenderingContext2D, backCanvasCreator: (width: number, height: number) => OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D): Adapter_Interface.IRenderAdapter
    {
        return new Adapter_Impl_Canvas2d.RenderAdapter_Canvas2d(rootCanvas, backCanvasCreator);
    }
}